Skip to content

Fixed faceted viewlet broken because sessions format changed from list to OrderedDict.#26

Merged
gbastien merged 4 commits intomainfrom
PARAF-345/2_fix_faceted_viewlet_sessions_format
Mar 16, 2026
Merged

Fixed faceted viewlet broken because sessions format changed from list to OrderedDict.#26
gbastien merged 4 commits intomainfrom
PARAF-345/2_fix_faceted_viewlet_sessions_format

Conversation

@gbastien
Copy link
Member

@gbastien gbastien commented Mar 16, 2026

See #PARAF-345

Summary by CodeRabbit

  • Bug Fixes

    • Restored faceted viewlet after session format changes.
    • Improved session retrieval with caching for more consistent, faster views.
    • Missing sessions now return an empty result instead of null; session data is copied for read-only access to prevent accidental modification.
  • Documentation

    • Added changelog entry noting the faceted viewlet fix and session-handling updates.

@coderabbitai
Copy link

coderabbitai bot commented Mar 16, 2026

📝 Walkthrough

Walkthrough

Fixes session-shape regressions: introduces a readonly-aware get_session_info, updates session retrieval in listing/viewlet to return cached dicts keyed by session id (or {}), and adds a changelog entry documenting the faceted viewlet fix.

Changes

Cohort / File(s) Summary
Changelog Entry
CHANGES.rst
Adds unreleased entry documenting fix: faceted viewlet broken after sessions format changed from list to OrderedDict.
Browser views
src/imio/esign/browser/views.py
Imports get_session_info; SessionsListingView.sessions and FacetedSessionInfoViewlet.sessions now parse safely, cache results in _cached_session, and return a dict {session_id: get_session_info(session_id)} or {} instead of lists; removed deepcopy-based copying.
Session utility
src/imio/esign/utils.py
Adds/updates get_session_info(session_id, portal=None, readonly=True); constructs a local session object, returns a deepcopy when readonly=True, and returns {} for missing sessions.
Tests
src/imio/esign/tests/test_utils.py
Adjusts tests to expect {} for non-existent session IDs from get_session_info instead of None.
Manifest / metadata
MANIFEST*
Minor manifest adjustments (lines changed: +2/-0).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • sgeulette

Poem

🐰 I hopped through session keys with care,
Swapped lists to maps and fetched a share,
Cached a silent token, tidy and neat,
Facets now wake with steps so fleet,
A rabbit's cheer for fixes complete. 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main fix: addressing a broken faceted viewlet caused by a sessions data format change from list to OrderedDict.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch PARAF-345/2_fix_faceted_viewlet_sessions_format
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/imio/esign/browser/views.py (1)

223-226: Cache the invalid session_id fallback too (minor optimization).

On Line 226, {} is returned without setting _cached_session, so repeated template/property accesses redo parsing.

Suggested small diff
         try:
             session_id = int(session_id)
         except (TypeError, ValueError):
-            return {}
+            self._cached_session = {}
+            return self._cached_session
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/imio/esign/browser/views.py` around lines 223 - 226, The code returns an
empty dict on invalid session_id but doesn't set the cached value, causing
repeated parsing; update the exception branch in the session_id parsing block
(where session_id = int(session_id) is tried) to assign self._cached_session =
{} (or the appropriate cache container) before returning so subsequent accesses
use the cached fallback; ensure this change is applied in the method that uses
self._cached_session in views.py so the invalid-session path is cached.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/imio/esign/browser/views.py`:
- Around line 223-226: The code returns an empty dict on invalid session_id but
doesn't set the cached value, causing repeated parsing; update the exception
branch in the session_id parsing block (where session_id = int(session_id) is
tried) to assign self._cached_session = {} (or the appropriate cache container)
before returning so subsequent accesses use the cached fallback; ensure this
change is applied in the method that uses self._cached_session in views.py so
the invalid-session path is cached.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1f24efc6-e843-4960-ae15-2b1157c74d0a

📥 Commits

Reviewing files that changed from the base of the PR and between 63a035f and 9419c98.

📒 Files selected for processing (3)
  • CHANGES.rst
  • src/imio/esign/browser/views.py
  • src/imio/esign/utils.py

…this way, change FacetedSessionInfoViewlet.sessions
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/imio/esign/browser/views.py`:
- Around line 219-230: The code builds and caches a mapping {session_id:
get_session_info(session_id)} without checking whether get_session_info returned
a valid session, causing a truthy empty-mapping to be returned; update the logic
in the view method that uses self._cached_session and session_id to call
get_session_info(session_id), check if the returned session is truthy (not
None/empty), and only then set and return {session_id: session}; if
get_session_info returns falsy, return {} (and avoid caching an invalid
mapping).

In `@src/imio/esign/utils.py`:
- Around line 334-347: The change made get_session_info(session_id, portal=None,
readonly=True) to deepcopy sessions by default which alters shared utility
semantics; revert the default readonly to False in get_session_info and ensure
deepcopy is only performed when readonly is explicitly True (keep usage of
deepcopy inside get_session_info guarded by the readonly flag), and move any
read-only deepcopy usage from callers (e.g., the viewlet) into the viewlet code
so callers that expect the live session mapping continue to receive the original
mapping returned by get_session_annotation and the session variable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 01406bb4-850b-414e-9908-78043e88ccbb

📥 Commits

Reviewing files that changed from the base of the PR and between 9419c98 and 02932dd.

📒 Files selected for processing (2)
  • src/imio/esign/browser/views.py
  • src/imio/esign/utils.py

Comment on lines +334 to +347
def get_session_info(session_id, portal=None, readonly=True):
"""Return a session info for a given numbering.

:param session_id: the session id to return
:param portal: portal if necessary to get the session annotation
:param readonly: return a copy of stored data to avoid modifying it
"""
annot = get_session_annotation(portal=portal)
session = {}
if session_id in annot['sessions']:
return annot['sessions'][session_id]
session = annot['sessions'][session_id]
if readonly:
session = deepcopy(session)
return session
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid changing get_session_info semantics in this PR.

This introduces a default deepcopy behavior in a shared utility, which is broader than the PR objective and can break callers expecting a live session mapping.

💡 Suggested adjustment
-def get_session_info(session_id, portal=None, readonly=True):
+def get_session_info(session_id, portal=None):
@@
-    if session_id in annot['sessions']:
-        session = annot['sessions'][session_id]
-        if readonly:
-            session = deepcopy(session)
+    if session_id in annot['sessions']:
+        session = annot['sessions'][session_id]
     return session

If read-only behavior is needed for the viewlet, apply deepcopy in the viewlet only.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def get_session_info(session_id, portal=None, readonly=True):
"""Return a session info for a given numbering.
:param session_id: the session id to return
:param portal: portal if necessary to get the session annotation
:param readonly: return a copy of stored data to avoid modifying it
"""
annot = get_session_annotation(portal=portal)
session = {}
if session_id in annot['sessions']:
return annot['sessions'][session_id]
session = annot['sessions'][session_id]
if readonly:
session = deepcopy(session)
return session
def get_session_info(session_id, portal=None):
"""Return a session info for a given numbering.
:param session_id: the session id to return
:param portal: portal if necessary to get the session annotation
"""
annot = get_session_annotation(portal=portal)
session = {}
if session_id in annot['sessions']:
session = annot['sessions'][session_id]
return session
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/imio/esign/utils.py` around lines 334 - 347, The change made
get_session_info(session_id, portal=None, readonly=True) to deepcopy sessions by
default which alters shared utility semantics; revert the default readonly to
False in get_session_info and ensure deepcopy is only performed when readonly is
explicitly True (keep usage of deepcopy inside get_session_info guarded by the
readonly flag), and move any read-only deepcopy usage from callers (e.g., the
viewlet) into the viewlet code so callers that expect the live session mapping
continue to receive the original mapping returned by get_session_annotation and
the session variable.

@gbastien
Copy link
Member Author

@chris-adam juste le fix pour le viewlet dans faceted, j'ai aussi ajouté le readonly sur utils.get_session_info "à la" utils.get_sessions_for et ajouté du cache soft vu que la méthode est appelée 2 fois, attention avec @Property, c'est calculé à chaque fois qu'on l'appelle comme une méthode, donc parfois on peut mettre du cache, en cachant localement dans un attr sur le viewlet, c'est non persistant (db) et très rapide car "ram.cache", est parfois + lent que le code qui est exécuté
Je propose de merger rapidement et faire le reste dans le ticket "ajout test" créé récemment

… found, so we can iterate on it instead returning None that must be managed specifically
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/imio/esign/browser/views.py (1)

224-225: Cache the invalid-input branch for consistent soft-cache behavior.

Line 225 returns {} without populating _cached_session, so repeated property access still reparses input. Consider caching {} here too for consistency with the rest of this method.

♻️ Suggested patch
         try:
             session_id = int(session_id)
         except (TypeError, ValueError):
-            return {}
+            self._cached_session = {}
+            return self._cached_session
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/imio/esign/browser/views.py` around lines 224 - 225, The except branch
returns {} without storing it in the cache, so repeated accesses re-run parsing;
update the except (TypeError, ValueError) block in the same function/property
that uses _cached_session to assign _cached_session = {} before returning so the
empty result is cached consistently (refer to the _cached_session variable and
the method/property that previously sets and returns it).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/imio/esign/browser/views.py`:
- Around line 224-225: The except branch returns {} without storing it in the
cache, so repeated accesses re-run parsing; update the except (TypeError,
ValueError) block in the same function/property that uses _cached_session to
assign _cached_session = {} before returning so the empty result is cached
consistently (refer to the _cached_session variable and the method/property that
previously sets and returns it).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a4612c74-5b42-4c7f-90d6-0cc868fa9d59

📥 Commits

Reviewing files that changed from the base of the PR and between ee477e5 and ad2a6d7.

📒 Files selected for processing (1)
  • src/imio/esign/browser/views.py

@gbastien gbastien merged commit 6730ff2 into main Mar 16, 2026
3 checks passed
@gbastien gbastien deleted the PARAF-345/2_fix_faceted_viewlet_sessions_format branch March 16, 2026 14:19
@chris-adam
Copy link
Contributor

@chris-adam juste le fix pour le viewlet dans faceted, j'ai aussi ajouté le readonly sur utils.get_session_info "à la" utils.get_sessions_for et ajouté du cache soft vu que la méthode est appelée 2 fois, attention avec @Property, c'est calculé à chaque fois qu'on l'appelle comme une méthode, donc parfois on peut mettre du cache, en cachant localement dans un attr sur le viewlet, c'est non persistant (db) et très rapide car "ram.cache", est parfois + lent que le code qui est exécuté Je propose de merger rapidement et faire le reste dans le ticket "ajout test" créé récemment

@gbastien Ok, et qu'est-ce que tu penses du décorateur cachedproperty ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants